/**
 * 版权所有，侵权必究！
 */

package com.commons.tools.utils;

import org.apache.commons.lang3.*;
import org.slf4j.*;

import javax.servlet.http.*;
import java.io.*;
import java.net.*;
import java.util.regex.*;

/**
 * IP工具类
 *
 * @author
 * @since 1.0.0
 */
public class IpUtils {
	private static Logger logger = LoggerFactory.getLogger(IpUtils.class);
	
	private static final int SSH_PORT_LINUX = 22;
    private static final int SSH_PORT_WINDOWS = 5985;   //windows:3389(RDP); windows:5985(winRM)
    
    private static final String OS_LINUX = "Linux";
    private static final String OS_WINDOWS = "Windows";
    private static final String OS_AIX = "AIX";
    private static final String OS_VIOS = "VIOS";

	public static String getIpAddr(HttpServletRequest request) {
    	String ip = null;
        try {
            ip = request.getHeader("x-forwarded-for");
            if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("Proxy-Client-IP");
            }
            if (StringUtils.isEmpty(ip) || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("WL-Proxy-Client-IP");
            }
            if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_CLIENT_IP");
            }
            if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_X_FORWARDED_FOR");
            }
            if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getRemoteAddr();
            }
        } catch (Exception e) {
        	logger.error("IpUtils ERROR ", e);
        }
        
        return ip;
    }
	
	public static boolean isReachable(String ip) {
        boolean reachable = false;
        int port = SSH_PORT_LINUX;
        reachable = isReachable(ip, port);
        if (!reachable) {
            port = SSH_PORT_WINDOWS;
            reachable = isReachable(ip, port);
        }
        return reachable;
    }
	
	public static boolean isReachable(String ip, int port) {
        int timeout = 10000;
        boolean reachable = false;
        logger.info("check ip reachable for ip: {}, port: {}", ip, port);
        try(Socket soc = new Socket()) {
            soc.connect(new InetSocketAddress(ip, port), timeout);
            reachable = true;
        } catch (IOException e1) {
            logger.warn("check ip({}) using port {} reachable exception: The IP is NOT reachable now.", ip, port);
        }

        return reachable;
    }
	
    public static boolean isReachable(String osType, String ip) {
        if (osType == null || osType.trim().isEmpty()) {
            return isReachable(ip);
        }
        int port = SSH_PORT_LINUX;
        if (osType.equals(OS_WINDOWS)) {
            port = SSH_PORT_WINDOWS;
        }
        return isReachable(ip, port);
    }
    
    /**
     * @param ips ip addresses, using ',' separated
     * @return
     */
    public static boolean areReachable(String ips) {
        logger.info("checkVmReachable for ips: {}", ips);
        String[] ipArray = ips.split(",");
        for (String ip : ipArray) {
            if (isReachable(ip)) {
                return true;
            }
        }
        return false;
    }
    
    /**
     * @param osType
     * @param ips    ip addresses, using ',' separated
     * @return
     */
    public static boolean areReachable(String osType, String ips) {
        if (osType == null || osType.trim().isEmpty()) {
            return areReachable(ips);
        }
        logger.info("checkVmReachable for ips: {}, osType: {}", ips, osType);
        String[] ipArray = ips.split(",");
        for (String ip : ipArray) {
            if (isReachable(osType, ip)) {
                return true;
            }
        }
        return false;
    }
    
    public static boolean isIp(String addr) {
        if (StringUtils.isBlank(addr) || addr.length() < 7 || addr.length() > 15) {
            return false;
        }
        String regex = "([1-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3}";
        return Pattern.compile(regex).matcher(addr).find();
    }

    public static String ipToLong(String ipAddress) {
        long result = 0;
        String[] ipAddressInArray = ipAddress.split("\\.");
        for (int i = 3; i >= 0; i--) {
            long ip = Long.parseLong(ipAddressInArray[3 - i]);
            result |= ip << (i * 8);
        }
        return Long.toHexString(result);
    }

    public static String ipToHexString(String ipString) {
        if(StringUtils.isBlank(ipString)){
            return null;
        }
        String[] ip=ipString.split("\\.");
        StringBuilder sb = new StringBuilder();
        for (String str : ip) {
            String hexString = Integer.toHexString(Integer.parseInt(str));
            if (hexString.length() < 2) {
                hexString = "0" + hexString;
            }
            sb.append(hexString);
        }
        return sb.toString();
    }

    public static long getLongValueFromIPStr(String ipStr){
        String[] ip = ipStr.split("\\.");
        return (Long.parseLong(ip[0])<<24) + (Long.parseLong(ip[1])<<16) + (Long.parseLong(ip[2])<<8) + (Long.parseLong(ip[3]));
    }

    public static String getIpFromLongValue(long ipIntValue){
        StringBuilder builder = new StringBuilder();
        builder.append(String.valueOf(ipIntValue >> 24) + ".");
        builder.append(String.valueOf((ipIntValue & 0x00FFFFFF) >> 16) + ".");
        builder.append(String.valueOf((ipIntValue & 0x0000FFFF) >> 8) + ".");
        builder.append(String.valueOf((ipIntValue & 0x000000FF) ) );
        return builder.toString();
    }
}
